﻿using GalaSoft.MvvmLight.Command;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Reflection.Emit;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Threading;
using OpenFileDialog = System.Windows.Forms.OpenFileDialog;

namespace AutoStar.ViewModel
{
    public class WindowImportGCodeVM : BaseViewModel
    {
        public ICommand GCodeImportCommand { get; private set; }
        public ICommand GCodeSendCommand { get; private set; }
        public ICommand AllGCodeSendCommand { get; private set; }

        public WindowImportGCodeVM()
        {
            GCodeImportCommand = new RelayCommand(GCode_ImportButton_Click);
            GCodeSendCommand = new RelayCommand(GCode_SendButton_Click);
            AllGCodeSendCommand = new RelayCommand(AllGCode_SendButton_Click);
        }
        List<List<string>> convertedLayers = new List<List<string>>();
        public void GCode_ImportButton_Click()
        {
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.Filter = "GCode文件|*.gcode";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                string contentPath = dialog.FileName;
                double first_layer_height = 0.0;
                double layer_height = 0.0;

                using (StreamReader sr = new StreamReader(contentPath))
                {
                    string line;
                    List<List<string>> layers = new List<List<string>>();
                    List<string> currentLayer = new List<string>();

                    while ((line = sr.ReadLine()) != null)
                    {
                        if (string.IsNullOrWhiteSpace(line)) continue;

                        if (line.Contains("; first_layer_height"))
                        {
                            first_layer_height = ExtractValue(line);
                            continue;
                        }
                        if (line.Contains("; layer_height"))
                        {
                            layer_height = ExtractValue(line);
                            continue;
                        }

                        if (line.Contains(";"))
                            line = line.Substring(0, line.IndexOf(';'));

                        if (Regex.IsMatch(line, @"^G1\s+X[^\s]+\s+Y[^\s]+\s+E[^\s]+$"))
                        {
                            currentLayer.Add(line);
                        }

                        if (line.StartsWith("G92 E0"))
                        {
                            if (currentLayer.Count > 0)
                            {
                                layers.Add(currentLayer);
                                currentLayer = new List<string>();
                            }
                        }
                    }

                    if (currentLayer.Count > 0)
                    {
                        layers.Add(currentLayer);
                    }

                    convertedLayers = ConvertGCode(layers, first_layer_height, layer_height);

                    // 直接将convertedLayers赋值给GCodeList
                    GCodeList = new ObservableCollection<string>(convertedLayers.SelectMany(layer => layer).ToList());
                }
            }
        }

        private double ExtractValue(string line)
        {
            string[] parts = line.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
            if (parts.Length >= 2 && double.TryParse(parts[1].Trim(), out double value))
            {
                return value;
            }
            return 0;
        }

        private List<List<string>> ConvertGCode(List<List<string>> layers, double firstLayerHeight, double layerHeight)
        {
            List<List<string>> convertedLayers = new List<List<string>>();
            double currentZ = firstLayerHeight;

            foreach (var layer in layers)
            {
                List<string> convertedLayer = new List<string>();
                int validMoveCount = 0;

                foreach (var move in layer)
                {
                    string[] items = move.Split(' ');
                    double x = 0, y = 0, z = 0;

                    foreach (var item in items)
                    {
                        if (item.StartsWith("X"))
                        {
                            double.TryParse(item.Substring(1), out x);
                        }
                        else if (item.StartsWith("Y"))
                        {
                            double.TryParse(item.Substring(1), out y);
                        }
                        else if (item.StartsWith("Z"))
                        {
                            double.TryParse(item.Substring(1), out z);
                        }
                    }

                    // 只保留有效的移动指令
                    if (x > 0 || y > 0 || z > 0)
                    {
                        validMoveCount++;
                    }

                    // 保留小数点后一位
                    string formattedX = x.ToString("0.0");
                    string formattedY = y.ToString("0.0");
                    string formattedZ = currentZ.ToString("0.0");

                    convertedLayer.Add($"G0X{formattedX}Y{formattedY}Z{formattedZ}E");
                }

                // 如果有效移动指令超过2条，则保留该层
                if (validMoveCount > 2)
                {
                    convertedLayers.Add(convertedLayer);
                }

                // Z轴上升并准备下一层
                currentZ += layerHeight;
            }

            return convertedLayers;
        }

        public void GCode_SendButton_Click()
        {
            // 在发送前为每一层添加开始和结束指令
            var modifiedGCodeList = new ObservableCollection<string>();
            foreach (var layer in convertedLayers)
            {
                // 添加每层开始前的特定指令
                modifiedGCodeList.Add("T2");
                modifiedGCodeList.Add("G1P83.9");
                modifiedGCodeList.Add("G1F600.0");
                modifiedGCodeList.Add("G1W3.0V10.0U100.0");

                // 添加当前层的移动指令
                foreach (var code in layer)
                {
                    modifiedGCodeList.Add(code);
                }

                // 每层结束后的气压归零指令
                modifiedGCodeList.Add("G1P3.7");
            }

            // 发送修改后的GCodeList
            foreach (var gCodeCommand in modifiedGCodeList)
            {
                int i = Global.printer.serialPortController.sendGCode(gCodeCommand);
                if (i == 0)
                {
                    System.Windows.MessageBox.Show("GCode发送成功！");
                }
                else if (i == 1)
                {
                    System.Windows.MessageBox.Show("串口未打开！");
                }
                else
                {
                    // 处理其他错误情况
                    System.Windows.MessageBox.Show("GCode发送失败！");
                }
            }
            System.Windows.MessageBox.Show("GCode发送成功！");
        }

        public void GCode_ListBox_SelectionChanged()
        {
            // 无需修改
        }

        private void AllGCode_SendButton_Click()
        {
            var result = System.Windows.MessageBox.Show("确认只发送包含移动指令吗？", "确认", MessageBoxButton.YesNo);
            if (result == MessageBoxResult.Yes)
            {
                GCodeList = new ObservableCollection<string>(GCodeList.Where(gcode => gcode.Contains("G1X")).ToList());
            }
            Global.MainVM.setChannel(ChannelIndex);
            Thread thread = new Thread(() =>
            {
                for (int i = 0; i < GCodeList.Count; i++)
                {
                    Global.printer.serialPortController.sendGCode((string)GCodeList[i]);
                    GCode_Label2 = i.ToString() + "/" + GCodeList.Count + "\r\n" + GCodeList[i].ToString();
                }
            });
            thread.Start();
            Global.MainVM.setChannel(6);
        }


        private ObservableCollection<string> _ChannelList = new ObservableCollection<string> { "通道1", "通道2", "通道3", "通道4", "通道5", "通道6" };
        public ObservableCollection<string> ChannelList
        {
            get => _ChannelList;
            set => Set(ref _ChannelList, value);
        }

        private int _ChannelIndex;
        public int ChannelIndex
        {
            get => _ChannelIndex;
            set => Set(ref _ChannelIndex, value);
        }

        private ObservableCollection<string> _GCodeList = new ObservableCollection<string>();
        public ObservableCollection<string> GCodeList
        {
            get => _GCodeList;
            set => Set(ref _GCodeList, value);
        }

        private string _GCode_Label2 = "0";
        public string GCode_Label2
        {
            get => _GCode_Label2;
            set => Set(ref _GCode_Label2, value);
        }

        private string _GCodeList_SelectedValue;
        public string GCodeList_SelectedValue
        {
            get => _GCodeList_SelectedValue;
            set => Set(ref _GCodeList_SelectedValue, value);
        }
    }
}
